OstreeSysroot *sysroot;
GFile *config_path_bios;
+ GFile *config_path_efi;
+ gboolean is_efi;
};
typedef GObjectClass OstreeBootloaderGrub2Class;
G_IMPLEMENT_INTERFACE (OSTREE_TYPE_BOOTLOADER, _ostree_bootloader_grub2_bootloader_iface_init));
static gboolean
-_ostree_bootloader_grub2_query (OstreeBootloader *bootloader)
+_ostree_bootloader_grub2_query (OstreeBootloader *bootloader,
+ gboolean *out_is_active,
+ GCancellable *cancellable,
+ GError **error)
{
+ gboolean ret = FALSE;
OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader);
+ gs_unref_object GFile* efi_basedir = NULL;
+ gs_unref_object GFileInfo *file_info = NULL;
+
+ if (g_file_query_exists (self->config_path_bios, NULL))
+ {
+ *out_is_active = TRUE;
+ ret = TRUE;
+ goto out;
+ }
+
+ efi_basedir = g_file_resolve_relative_path (self->sysroot->path, "boot/efi/EFI");
+
+ g_clear_object (&self->config_path_efi);
+
+ if (g_file_query_exists (efi_basedir, NULL))
+ {
+ gs_unref_object GFileEnumerator *direnum = NULL;
+
+ direnum = g_file_enumerate_children (efi_basedir, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable, error);
+ if (!direnum)
+ goto out;
+
+ while (TRUE)
+ {
+ GFileInfo *file_info;
+ const char *fname;
+ gs_free char *subdir_grub_cfg = NULL;
+
+ if (!gs_file_enumerator_iterate (direnum, &file_info, NULL,
+ cancellable, error))
+ goto out;
+ if (file_info == NULL)
+ break;
+
+ fname = g_file_info_get_name (file_info);
+ if (strcmp (fname, "BOOT") == 0)
+ continue;
+
+ if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
+ continue;
+
+ subdir_grub_cfg = g_build_filename (gs_file_get_path_cached (efi_basedir), fname, "grub.cfg", NULL);
+
+ if (g_file_test (subdir_grub_cfg, G_FILE_TEST_EXISTS))
+ {
+ self->config_path_efi = g_file_new_for_path (subdir_grub_cfg);
+ break;
+ }
+ }
+
+ if (self->config_path_efi)
+ {
+ self->is_efi = TRUE;
+ *out_is_active = TRUE;
+ ret = TRUE;
+ goto out;
+ }
+ }
+ else
+ *out_is_active = FALSE;
- return g_file_query_exists (self->config_path_bios, NULL);
+ ret = TRUE;
+ out:
+ return ret;
}
static const char *
}
gboolean
-_ostree_bootloader_grub2_generate_config (OstreeBootloaderGrub2 *self,
+_ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot,
int bootversion,
int target_fd,
GCancellable *cancellable,
gs_unref_ptrarray GPtrArray *loader_configs = NULL;
guint i;
gsize bytes_written;
+ gboolean is_efi;
/* So... yeah. Just going to hardcode these. */
static const char hardcoded_video[] = "load_video\n"
"set gfxpayload=keep\n";
g_assert (grub2_boot_device_id != NULL);
g_assert (grub2_prepare_root_cache != NULL);
+ /* Passed from the parent */
+ is_efi = g_getenv ("_OSTREE_GRUB2_IS_EFI") != NULL;
+
out_stream = g_unix_output_stream_new (target_fd, FALSE);
- if (!_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion,
+ if (!_ostree_sysroot_read_boot_loader_configs (sysroot, bootversion,
&loader_configs,
cancellable, error))
goto out;
"No \"linux\" key in bootloader config");
goto out;
}
- g_string_append (output, "linux16 ");
+ if (is_efi)
+ g_string_append (output, "linuxefi ");
+ else
+ g_string_append (output, "linux16 ");
g_string_append (output, kernel);
options = ostree_bootconfig_parser_get (config, "options");
initrd = ostree_bootconfig_parser_get (config, "initrd");
if (initrd)
{
- g_string_append (output, "initrd16 ");
+ if (is_efi)
+ g_string_append (output, "initrdefi ");
+ else
+ g_string_append (output, "initrd16 ");
g_string_append (output, initrd);
g_string_append_c (output, '\n');
}
{
OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader);
gboolean ret = FALSE;
+ gs_unref_object GFile *efi_new_config_temp = NULL;
+ gs_unref_object GFile *efi_orig_config = NULL;
gs_unref_object GFile *new_config_path = NULL;
gs_unref_object GSSubprocessContext *procctx = NULL;
gs_unref_object GSSubprocess *proc = NULL;
gs_strfreev char **child_env = g_get_environ ();
gs_free char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion);
+ gs_unref_object GFile *config_path_efi_dir = NULL;
- new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/grub.cfg",
- bootversion);
+ if (self->is_efi)
+ {
+ config_path_efi_dir = g_file_get_parent (self->config_path_efi);
+ new_config_path = g_file_get_child (config_path_efi_dir, "grub.cfg.new");
+ /* We use grub2-mkconfig to write to a temporary file first */
+ if (!ot_gfile_ensure_unlinked (new_config_path, cancellable, error))
+ goto out;
+ }
+ else
+ {
+ new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/grub.cfg",
+ bootversion);
+ }
procctx = gs_subprocess_context_newv ("grub2-mkconfig", "-o",
gs_file_get_path_cached (new_config_path),
NULL);
child_env = g_environ_setenv (child_env, "_OSTREE_GRUB2_BOOTVERSION", bootversion_str, TRUE);
+ /* We have to pass our state to the child */
+ if (self->is_efi)
+ child_env = g_environ_setenv (child_env, "_OSTREE_GRUB2_IS_EFI", "1", TRUE);
gs_subprocess_context_set_environment (procctx, child_env);
gs_subprocess_context_set_stdout_disposition (procctx, GS_SUBPROCESS_STREAM_DISPOSITION_NULL);
if (g_getenv ("OSTREE_DEBUG_GRUB2"))
/* Now let's fdatasync() for the new file */
if (!gs_file_sync_data (new_config_path, cancellable, error))
goto out;
+
+ if (self->is_efi)
+ {
+ gs_unref_object GFile *config_path_efi_old = g_file_get_child (config_path_efi_dir, "grub.cfg.old");
+
+ /* copy current to old */
+ if (!ot_gfile_ensure_unlinked (config_path_efi_old, cancellable, error))
+ goto out;
+ if (!g_file_copy (self->config_path_efi, config_path_efi_old,
+ G_FILE_COPY_OVERWRITE, cancellable, NULL, NULL, error))
+ goto out;
+ if (!ot_gfile_ensure_unlinked (config_path_efi_old, cancellable, error))
+ goto out;
+
+ /* NOTE: NON-ATOMIC REPLACEMENT; WE can't do anything else on FAT;
+ * see https://bugzilla.gnome.org/show_bug.cgi?id=724246
+ */
+ if (!ot_gfile_ensure_unlinked (new_config_path, cancellable, error))
+ goto out;
+ if (!gs_file_rename (new_config_path, self->config_path_efi,
+ cancellable, error))
+ goto out;
+ }
ret = TRUE;
out:
static gboolean
_ostree_bootloader_grub2_is_atomic (OstreeBootloader *bootloader)
{
- return TRUE;
+ OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader);
+ return !self->is_efi;
}
static void
g_clear_object (&self->sysroot);
g_clear_object (&self->config_path_bios);
+ g_clear_object (&self->config_path_efi);
G_OBJECT_CLASS (_ostree_bootloader_grub2_parent_class)->finalize (object);
}
/**
* ostree_sysroot_query_bootloader:
* @sysroot: Sysroot
- *
- * Returns: (transfer full): Currently active bootloader in @sysroot
+ * @out_bootloader: (out) (transfer full) (allow-none): Return location for bootloader, may be %NULL
+ * @cancellable: Cancellable
+ * @error: Error
*/
-OstreeBootloader *
-_ostree_sysroot_query_bootloader (OstreeSysroot *self)
+gboolean
+_ostree_sysroot_query_bootloader (OstreeSysroot *sysroot,
+ OstreeBootloader **out_bootloader,
+ GCancellable *cancellable,
+ GError **error)
{
- OstreeBootloaderSyslinux *syslinux;
- OstreeBootloaderUboot *uboot;
- OstreeBootloaderGrub2 *grub2;
-
- syslinux = _ostree_bootloader_syslinux_new (self);
- if (_ostree_bootloader_query ((OstreeBootloader*)syslinux))
- return (OstreeBootloader*) (syslinux);
-
- grub2 = _ostree_bootloader_grub2_new (self);
- if (_ostree_bootloader_query ((OstreeBootloader*)grub2))
- return (OstreeBootloader*) (grub2);
+ gboolean ret = FALSE;
+ gboolean is_active;
+ gs_unref_object OstreeBootloader *ret_loader = NULL;
- uboot = _ostree_bootloader_uboot_new (self);
- if (_ostree_bootloader_query ((OstreeBootloader*)uboot))
- return (OstreeBootloader*) (uboot);
+ ret_loader = (OstreeBootloader*)_ostree_bootloader_syslinux_new (sysroot);
+ if (!_ostree_bootloader_query (ret_loader, &is_active,
+ cancellable, error))
+ goto out;
+ if (!is_active)
+ {
+ g_object_unref (ret_loader);
+ ret_loader = (OstreeBootloader*)_ostree_bootloader_grub2_new (sysroot);
+ if (!_ostree_bootloader_query (ret_loader, &is_active,
+ cancellable, error))
+ goto out;
+ }
+ if (!is_active)
+ {
+ g_object_unref (ret_loader);
+ ret_loader = (OstreeBootloader*)_ostree_bootloader_uboot_new (sysroot);
+ if (!_ostree_bootloader_query (ret_loader, &is_active, cancellable, error))
+ goto out;
+ }
+ if (!is_active)
+ g_clear_object (&ret_loader);
- return NULL;
+ ret = TRUE;
+ gs_transfer_out_value (out_bootloader, &ret_loader);
+ out:
+ return ret;
}
char *